home *** CD-ROM | disk | FTP | other *** search
/ SPACE 1 / SPACE - Library 1 - Volume 1.iso / misc~1 / 199 / lib / lib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-03-14  |  24.7 KB  |  1,292 lines

  1. /* C library - startup, stdio, strings, TOS */
  2.  
  3. /* max number of args in argv[] */
  4.  
  5. #define MAXARG    50
  6.  
  7. /* header file for stdio implementation */
  8.  
  9. #define MAXBUF    512
  10. #define MAXIO    6
  11.  
  12. struct file {
  13.     char    mode;        /* free or open for read/write         */
  14.     char    fd;        /* GEMTOS file descriptor        */
  15.     int    idx;        /* next slot in buf read/written    */
  16.     int    len;        /* length of the buffer            */
  17.     char    buf[MAXBUF];    /* i/o buffer                */
  18. };
  19.  
  20. /* these are the allowed modes */
  21.  
  22. #define FREE    0
  23. #define RD    1
  24. #define WR    2
  25. #define RDWR    3
  26.  
  27. /* these should match what's found in stdio.h, except for FILE */
  28.  
  29. #define FILE    struct file
  30. #define EOF    (-1)
  31. #define NULL    (0L)
  32. #define EOS    ((char)0)
  33.  
  34. /* these are the GEMDOS trap commands */
  35.  
  36. #define CREATE    0x3C
  37. #define OPEN    0x3D
  38. #define CLOSE    0x3E
  39. #define READ    0x3F
  40. #define WRITE    0x40
  41. #define LSEEK    0x42
  42. #define SETBLK    0x4A
  43. #define EXIT    0x4C
  44.  
  45. /* 
  46.  * the c runtime start up routine for ttp processes
  47.  *
  48.  * assumes a startup sttp.s of
  49.  *    . _bstk 2048
  50.  *    . _estk 4
  51.  *    taa 7 6
  52.  *    lll 4 0
  53.  *    sgl _estk
  54.  *    lag _estk 7
  55.  *    jsr _cttp
  56.  */
  57.  
  58. _cttp(tpa) long tpa; {
  59.  
  60.     extern int argc;
  61.     extern char *argv[MAXARG];
  62.     extern FILE *stdin, *stdout, *stderr;
  63.     extern FILE _iobuf[1];
  64.  
  65.     char *b, *w, *in, *out, *arge;
  66.     int i;
  67.     long x, *lp;
  68.  
  69.     /* compute size of program, give memory back to TOS */
  70.     lp = tpa;
  71.     x = lp[3] + lp[5] + lp[7] + 0x100;
  72.     if (trap(1, SETBLK, 0, tpa, x))
  73.         exit(-1);
  74.  
  75.     /* parse the command line */
  76.     argc = 1;
  77.     argv[0] = "yc";
  78.     arge = (char *) lp[11];
  79.     b = tpa + 0x81;
  80.     in = out = NULL;
  81.     while (*b) {
  82.         while (*b && *b <= ' ') b++;
  83.         w = b;
  84.         while (*b && *b > ' ') b++;
  85.         if (*b) *b++ = 0;
  86.         if (*w == '<') in = w+1;
  87.         else if (*w == '>') out = w+1;
  88.         else if (argc < MAXARG) argv[argc++] = w;
  89.     }
  90.     argv[argc] = 0L;
  91.  
  92.     /* init stdio */
  93.     for (i = 0; i < MAXIO; i++) {
  94.         _iobuf[i].mode = FREE;
  95.         _iobuf[i].fd = _iobuf[i].idx = _iobuf[i].len = 0;
  96.     }
  97.     stdin = &_iobuf[0];
  98.     stdout = &_iobuf[1];
  99.     stderr = &_iobuf[2];
  100.     stdin->mode = stdout->mode = stderr->mode = RDWR;
  101.     if (in) {
  102.         stdin->fd = i = trap(1, OPEN, in, 0);
  103.         stdin->mode = RD;
  104.         if (i < 0) _cant(in, i);
  105.     }
  106.     if (out) {
  107.         if (*out != '>') { /* create */
  108.             stdout->fd = i = trap(1, CREATE, out, 0);
  109.         }
  110.         else    { /* append */
  111.             stdout->fd = i = trap(1, OPEN, ++out, 1);
  112.             if (i >= 0) i = trap(1, LSEEK, 0L, i, 2);
  113.         }
  114.         stdout->mode = WR;
  115.         if (i < 0) _cant(out, i);
  116.     }
  117.     
  118.     /* run the program */
  119.     i = main(argc, argv, arge);
  120.  
  121.     /* close up shop */
  122.     if (in) fclose(stdin);
  123.     if (out) fclose(stdout);
  124.     exit(i);
  125. }
  126.  
  127. /* trouble redirecting output */
  128.  
  129. _cant(s, fd) char *s; {
  130.     _ps("can't redirect ");
  131.     _ps(s);
  132.     _ps("\n\r");
  133.     exit(fd);
  134. }
  135.  
  136. _ps(s) char *s; { while (*s) trap(1, 2, *s++); }
  137.  
  138. /* exit the program */
  139.  
  140. exit(n) { trap(1, EXIT, n); }
  141.  
  142. /* data for _cttp or _ctos */
  143.  
  144. int     argc;
  145. char     *argv[MAXARG];
  146.  
  147. FILE    _iobuf[MAXIO], *stdin,     *stdout, *stderr;
  148.  
  149. /* printf's (see below for the guts) */
  150.  
  151. char *_dopf();
  152.  
  153. fprintf(fp, fmt, args) FILE *fp; char *fmt; int args; {
  154.     extern char _pfb[256];
  155.     _dopf(_pfb, fmt, &args);
  156.     return fputs(_pfb, fp);
  157. }
  158.  
  159. printf(fmt, args) char *fmt; int args; {
  160.     extern char _pfb[256];
  161.     _dopf(_pfb, fmt, &args);
  162.     return fputs(_pfb, stdout);
  163. }
  164.  
  165. /*
  166.  * stdio routines 
  167.  */
  168.  
  169. /* return file descriptor of a stream */
  170.  
  171. fileno(s) FILE *s; { return s->fd; }
  172.  
  173. /* read a stream */
  174.  
  175. fread(buf, sz, n, s) char *buf; FILE *s; {
  176.     int r;
  177.     long nn;
  178.     nn = (long) n * (long) sz;
  179.     if ((r = trap(1, READ, s->fd, nn, buf)) < 0)
  180.         r = 0;
  181.     else    r = r / sz;
  182.     return r;
  183. }
  184.  
  185. /* write on a stream */
  186.  
  187. fwrite(buf, sz, n, s) char *buf; FILE *s; {
  188.     int r;
  189.     long nn;
  190.     nn = (long) n * (long) sz;
  191.     if ((r = trap(1, WRITE, s->fd, nn, buf)) < 0)
  192.         r = 0;
  193.     else    r = r / sz;
  194.     return r;
  195. }
  196.  
  197. /* seek and ye shall find */
  198.  
  199. fseek(s, offset, mode) FILE *s; long offset; {
  200.     lseek(s->fd, offset, mode);
  201. }
  202.  
  203. /* close a stream */
  204.  
  205. fclose(s) FILE *s; {
  206.     if (s != NULL) {
  207.         if (s->mode == WR) fflush(s);
  208.         if (s->fd) trap(1, CLOSE, s->fd);
  209.         s->mode = FREE;
  210.     }
  211. }
  212. /* flush out a buffer */
  213.  
  214. fflush(s) FILE *s; {
  215.     int r;
  216.     if (s->idx > 0) 
  217.         r = trap(1, WRITE, s->fd, (long) s->idx, s->buf);
  218.     s->idx = 0;
  219.     return r <= 0 ? EOF : r;
  220. }
  221.  
  222. /* get a string from a stream */
  223.  
  224. char *
  225. fgets(b, n, f) char *b; int n; FILE *f; {
  226.     int c, i;
  227.     c = getc(f);
  228.     if (c == EOF) return NULL;
  229.     n--;
  230.     for (i = 0; i < n && c != EOF; c = getc(f)) {
  231.         b[i++] = c;
  232.         if (c == '\n') break;
  233.     }
  234.     b[i] = 0;
  235.     return b;
  236. }
  237.  
  238. /* open a stream */
  239.  
  240. FILE *
  241. fopen(name, mode) char *name, *mode; {
  242.     int i, m, fd, x;
  243.     FILE *s;
  244.     for (i = 0; i < MAXIO && _iobuf[i].mode != FREE; i++)
  245.         ;
  246.     if (i >= MAXIO) return NULL;
  247.     if (*mode == 'w') {
  248.         fd = trap(1, CREATE, name, 0);
  249.         m = WR;
  250.     }
  251.     else if (*mode == 'r') {
  252.         fd = trap(1, OPEN, name, 0);
  253.         m = RD;
  254.     }
  255.     else if (*mode == 'a') {
  256.         if ((fd = trap(1, OPEN, name, 1)) < 0)
  257.             fd = trap(1, CREATE, name, 0);
  258.         else    if (trap(1, LSEEK, 0L, fd, 2) < 0L)
  259.             fd = -1;
  260.         m = WR;
  261.     }
  262.     else    { /* anything goes here, usually '+' */
  263.         fd = trap(1, OPEN, name, 3);
  264.         m = RDWR;
  265.     }
  266.     if (fd < 0) return NULL;
  267.     s = &_iobuf[i];
  268.     s->len = s->idx = 0;
  269.     s->fd = fd;
  270.     s->mode = m;
  271.     return s;
  272. }
  273.  
  274. /* put a string onto the stream */
  275.  
  276. fputs(s, f) char *s; FILE *f; {
  277.     while (*s) putc(*s++, f);
  278. }
  279.  
  280. /* get a string from stdin */
  281.  
  282. char *
  283. gets(b) char *b; {
  284.     int c;
  285.     char *r;
  286.     r = b;
  287.     if ((c = getc(stdin)) == EOF) return NULL;
  288.     while (c != '\n' && c != EOF) {
  289.         *b++ = c;
  290.         c = getc(stdin);
  291.     }
  292.     *b = 0;
  293.     return r;
  294. }
  295.  
  296. /* get a character from standard input */
  297.  
  298. getchar() { return getc(stdin); }
  299.  
  300. /* get a character from a stream */
  301.  
  302. getc(s) FILE *s; {
  303.     int i, l, c, r;
  304.     if (s == NULL) return EOF;
  305.     if (s->mode == RDWR) {
  306.         l = trap(1, READ, s->fd, (long) 1, s->buf);
  307.         if (l != 1) return EOF;
  308.         i = 0;
  309.     }
  310.     else if (s->mode == RD) {
  311.         i = s->idx;
  312.         while (i >= s->len) {
  313.             l = trap(1, READ, s->fd, (long) MAXBUF, s->buf);
  314.             if (l <= 0) {
  315.                 s->idx = s->len = 0;
  316.                 return EOF;
  317.             }
  318.             s->len = l;
  319.             i = 0;
  320.         }
  321.         s->idx = i + 1;
  322.     }
  323.     else    return EOF;
  324.     c = s->buf[i] & 255;
  325.     if (s->fd == 0 && c == '\r')
  326.         putc(c = '\n', s);
  327.     return c;
  328. }
  329.  
  330. /* output characters to a stream */
  331.  
  332. putchar(c) { putc(c, stdout); }
  333.  
  334. puts(s) char *s; {
  335.     while (*s) putc(*s++, stdout);
  336.     putc('\n', stdout);
  337. }
  338.  
  339. putc(c, s) int c; FILE *s; {
  340.     int i, r;
  341.     if (s == NULL) return EOF;
  342.     r = 0;
  343.     if (s->mode == RDWR) {
  344.         s->buf[0] = c;
  345.         r = trap(1, WRITE, s->fd, (long) 1, s->buf);
  346.     }
  347.     else if (s->mode == WR) {
  348.         if (s->idx == MAXBUF) r = fflush(s);
  349.         s->buf[s->idx] = c;
  350.         s->idx = s->idx + 1;
  351.     }
  352.     else     return EOF;
  353.     if (s->fd == 0 && c == '\n') r = putc('\r', s);
  354.     return r <= 0 ? EOF : r;
  355. }
  356.  
  357. /* 
  358.  * TOS routines 
  359.  */
  360.  
  361. /* duplicate a file descriptor */
  362.  
  363. dup(fd) { return trap(1, 0x45, fd); }
  364.  
  365. /*  execute a program: mode=0 -> load and go; mode=3 -> load and return  */
  366.  
  367. exec(file, args, env, mode) char *file, *args, *env; int mode; {
  368.     return trap(1, 0x4B, mode, file, args, env);
  369. }
  370.  
  371. /* get current directory: drive=0 -> current drive, drive=1 -> A:, etc */
  372.  
  373. getdir(buf, drive) char *buf; {
  374.     return trap(1, 0x47, buf, drive);
  375. }
  376.  
  377. /* 
  378.  * list the disk directory
  379.  *    pat != NULL - set the DTA buffer, do an SFIRST
  380.  *    pat == NULL - do a SNEXT
  381.  */
  382.  
  383. listdir(pat, buf, mode) char *pat, *buf; {
  384.     if (pat) {
  385.         trap(1, 0x1A, buf);
  386.         return trap(1, 0x4E, pat, mode);
  387.     }
  388.     else    return trap(1, 0x4F);
  389. }
  390.  
  391. /* seek to a position in a file */
  392.  
  393. lseek(fd, offset, mode) int fd; long offset; int mode; {
  394.     return trap(1, 0x42, offset, fd, mode);
  395. }
  396.  
  397. /* unlink a file */
  398.  
  399. unlink(name) char *name; { return trap(1, 0x41, name); }
  400.  
  401. /* close a file */
  402.  
  403. close(fd) { trap(1, 0x3E, fd); }
  404.  
  405. /* create a file */
  406.  
  407. creat(f, m) char *f; {
  408.     return trap(1, 0x3C, f, m);
  409. }
  410.  
  411. /* open a file */
  412.  
  413. open(f, m) char *f; {
  414.     return trap(1, 0x3D, f, m);
  415. }
  416.  
  417. /* read a file */
  418.  
  419. read(fd, buf, sz) int fd, sz; char *buf; {
  420.     return trap(1, 0x3F, fd, (long) sz, buf);
  421. }
  422.  
  423. /* unix-like write system call */
  424.  
  425. write(fd, buf, sz) int fd, sz; char *buf; {
  426.     return trap(1, 0x40, fd, (long) sz, buf);
  427. }
  428.  
  429. /* 
  430.  * chmod(name, mode)
  431.  * mode = 0x00 - normal file (read/write)
  432.  *        0x01 - read only file
  433.  *        0x02 - hidden file
  434.  *        0x04 - system file
  435.  *        0x08 - file is volume label
  436.  *        0x10 - file is a subdirectory
  437.  *        0x20 - file is written and closed correctly
  438.  */
  439.  
  440. chmod(name, mode) char *name; int mode; {
  441.     return trap(1, 0x43, name, mode, 0);
  442. }
  443.  
  444. /* guts of the printf stuff */
  445.  
  446. #define    MINUSFLG    1
  447. #define    PLUSFLG        2
  448. #define    BLANKFLG    4
  449. #define    POUNDFLG    8
  450. #define    ZEROFLG        16
  451. #define    LONGFLG        32
  452. #define    SIGNFLG        64
  453. #define    LOWERFLG    128
  454.  
  455. #define    MAXINT    32767
  456.  
  457. char    _pfb[256];    /* in case someone needs a buffer */
  458.  
  459. sprintf(buf, fmt, args)    char *buf, *fmt; int args; {
  460.     return _dopf(buf, fmt, &args) - buf;
  461. }
  462.  
  463. char *_numcnv();
  464.  
  465. char *
  466. _dopf(buf, fmt, i_p) char *buf, *fmt; int *i_p; {
  467.     char    c, **s_p, *s;
  468.     long    strtol();
  469.     int    i, lng, precision, minfldw, flags;
  470.  
  471.     for (c = *fmt; ; c = *++fmt) {
  472.         /* scan to next conversion specification */
  473.         while (c != '%') {
  474.             *buf++ = c;
  475.             if (c == EOS) {
  476.                 return buf - 1;
  477.             }
  478.             c = *++fmt;
  479.         }
  480.         c = *++fmt;
  481.         /* scan flags */
  482.         for (flags = 0; ; c = *++fmt) {
  483.             if (c == '-') flags |= MINUSFLG;
  484.             else if (c == '+') flags |= PLUSFLG;
  485.             else if (c == ' ') flags |= BLANKFLG;
  486.             else if (c == '#') flags |= POUNDFLG;
  487.             else break;
  488.         }
  489.         /* scan minimum field width */
  490.         if (c == '*') {
  491.             minfldw = *i_p++;
  492.             c = *++fmt;
  493.         }
  494.         else    {
  495.             if (c == '0') flags |= ZEROFLG;
  496.             minfldw = (int)strtol(fmt, &fmt, 10);
  497.             c = *fmt;
  498.         }
  499.         /* scan precision */
  500.         precision = -1;
  501.         if (c == '.') {
  502.             c = *++fmt;
  503.             if (c == '*') {
  504.                 precision = *i_p++;
  505.                 c = *++fmt;
  506.             }
  507.             else    {
  508.                 precision = (int)strtol(fmt, &fmt, 10);
  509.                 c = *fmt;
  510.             }
  511.         }
  512.         if (c == 'l') {
  513.             flags |= LONGFLG;
  514.             c = *++fmt;
  515.         }
  516.         switch (c) {
  517.         case 'd':
  518.             buf = _numcnv(buf, 10, flags | SIGNFLG, &i_p,
  519.                 precision, minfldw);
  520.             break;
  521.         case 'o':
  522.             buf = _numcnv(buf, 8, flags, &i_p, precision, minfldw);
  523.             break;
  524.         case 'u':
  525.             buf = _numcnv(buf, 10, flags, &i_p, precision, minfldw);
  526.             break;
  527.         case 'x':
  528.             flags |= LOWERFLG;
  529.         case 'X':
  530.             buf = _numcnv(buf, 16, flags, &i_p, precision, minfldw);
  531.             break;
  532.         case 'f':
  533.         case 'e':
  534.         case 'E':
  535.         case 'g':
  536.         case 'G':
  537.             /* someday, floats */
  538.             break;
  539.         case 'c':
  540.             *buf++ = *i_p++;
  541.             break;
  542.         case 's':
  543.             if (precision < 0) precision = MAXINT;
  544.             s_p = (char **)i_p;
  545.             s = *s_p++;
  546.             i_p = (int *)s_p;
  547.             for (lng = 0; s[lng] != EOS && lng < precision; ++lng);
  548.             i = minfldw - lng;
  549.             if ((flags & MINUSFLG) == 0) { /* right justify */
  550.                 while (i-- > 0) *buf++ = ' ';
  551.             }
  552.             while (lng--) *buf++ = *s++;
  553.             while (i-- > 0) *buf++ = ' ';
  554.             break;
  555.         case '%':
  556.         default:
  557.             *buf++ = c;
  558.             break;
  559.         }
  560.     }
  561. }
  562.  
  563. char *
  564. _numcnv(buf, base, flags, ip_p, precision, minfldw)
  565.     char    *buf;
  566.     unsigned int    base;
  567.     int    **ip_p;
  568. {
  569.     char    numbuf[20], prefix[5], *s, *p, *strncpy();
  570.     int    n, pad, lng, d;
  571.     long    value, *l_p;
  572.     unsigned long    uvalue;
  573.  
  574.     s = numbuf;
  575.     p = prefix;
  576.     if (flags & LONGFLG) {
  577.         l_p = (long *)*ip_p;
  578.         value = *l_p++;
  579.         *ip_p = (int *)l_p;
  580.     }
  581.     else    {
  582.         value = (long)**ip_p;
  583.         *ip_p += 1;
  584.     }
  585.     if (flags & SIGNFLG) {
  586.         if (value < 0) {
  587.             *p++ = '-';
  588.             value = -value;
  589.         }
  590.         else    {
  591.             if (flags & PLUSFLG) *p++ = '+';
  592.             else if (flags & BLANKFLG) *p++ = ' ';
  593.         }
  594.     }
  595.     uvalue = (unsigned long) value;
  596.     while (uvalue) {
  597.         d = uvalue % base;
  598.         *s++ = (d < 10) ? d + '0' 
  599.                 : d - 10 + ((flags & LOWERFLG) ? 'a' : 'A');
  600.         uvalue /= base;
  601.     }
  602.     lng = (int)(s - numbuf);
  603.     n = (int)(p - prefix);
  604.     pad = minfldw - n;
  605.     if (flags & ZEROFLG) precision = minfldw - n;
  606.     if (precision < 0) precision = 1;
  607.     if (flags & POUNDFLG) {
  608.         if (base == 8 && lng >= precision) precision = lng + 1;
  609.         else if (base == 16) {
  610.             *p++ = '0';
  611.             *p++ = flags & LOWERFLG ? 'x' : 'X';
  612.             n += 2;
  613.             precision -= 2;
  614.         }
  615.     }
  616.     pad -= lng > precision ? lng : precision;
  617.     if (pad < 0) pad = 0;
  618.     if ((flags & MINUSFLG) == 0) {
  619.         while (pad--) *buf++ = ' ';
  620.         pad = 0;
  621.     }
  622.     strncpy(buf, prefix, n);
  623.     buf += n;
  624.     while (precision-- > lng) *buf++ = '0';
  625.     while (lng--) *buf++ = *--s;
  626.     while (pad--) *buf++ = ' ';
  627.     return    buf;
  628. }
  629.  
  630. /* scanf routines */
  631.  
  632. fscanf(f, fmt, args) FILE *f; char *fmt; int *args; {
  633.     extern char *_sfcp;
  634.     extern FILE *_sffp;
  635.     _sffp = f;
  636.     _sfcp = NULL;
  637.     return _dosf(fmt, &args);
  638. }
  639.  
  640. scanf(fmt, args) char *fmt; int *args; {
  641.     extern char *_sfcp;
  642.     extern FILE *_sffp;
  643.     _sffp = stdin;
  644.     _sfcp = NULL;
  645.     return _dosf(fmt, &args);
  646. }
  647.  
  648. sscanf(s, fmt, args) char *s; char *fmt; int *args; {
  649.     extern char *_sfcp;
  650.     extern FILE *_sffp;
  651.     _sffp = NULL;
  652.     _sfcp = s;
  653.     return _dosf(fmt, &args);
  654. }
  655.         
  656. _dosf(fmt, args) char *fmt; int **args; {
  657.     int assigned, wid, lng, skip, *ip, f, c, m, base;
  658.     long n, *lp;
  659.     char *cp;
  660.     assigned = 0;
  661.     c = _sfget();
  662.     while ((f = *fmt++) && c != EOF) {
  663.         if (f <= ' ') { /* skip spaces */
  664.             while (c <= ' ' && c != EOF)
  665.                 c = _sfget();
  666.         }
  667.         else if (f != '%') { /* match character */
  668.             if (c != f) 
  669.                 return assigned;
  670.         }
  671.         else    {
  672.             wid = lng = skip = 0;
  673.             if ((f = *fmt++) == '*') { /* skip assignment */
  674.                 skip++;
  675.                 f = *fmt++;
  676.             }
  677.             while (f >= '0' && f <= '9') { /* width of value */
  678.                 wid = wid * 10 + f - '0';
  679.                 f = *fmt++;
  680.             }
  681.             if (f == 'l') { /* long */
  682.                 lng++;
  683.                 f = *fmt++;
  684.             }
  685.             else if (f == 'h') { /* short */
  686.                 f = *fmt++;
  687.             }
  688.             switch (f) { /* conversion spec */
  689.             case '%':
  690.                 if (c != '%') return assigned;
  691.                 c = _sfget();
  692.                 break;
  693.             case 'c':
  694.                 if (wid == 0) {
  695.                     cp = *args++;
  696.                     if (!skip) {
  697.                         *cp = c;
  698.                         assigned++;
  699.                     }
  700.                     c = _sfget();
  701.                     break;
  702.                 }
  703.             case 's':
  704.                 cp = *args++;
  705.                 while (c <= ' ' && c != EOF)
  706.                     c = _sfget();
  707.                 while (c > ' ' && c != EOF) {
  708.                     if (!skip) *cp++ = c;
  709.                     c = _sfget();
  710.                     if (--wid == 0) break;
  711.                 }
  712.                 *cp = 0;
  713.                 if (!skip) assigned++;
  714.                 break;
  715.             case 'D': case 'X': case 'O':
  716.                 lng = 1;
  717.                 f = f - 'A' + 'a';
  718.             case 'd': case 'x': case 'o':
  719.                 base = (f == 'x' ? 16 : f == 'o' ? 8 : 10);
  720.                 n = 0L;
  721.                 while (c != EOF && c <= ' ')
  722.                     c = _sfget();
  723.                 if ((m = _sfnum(c, base)) < 0)
  724.                     return assigned;
  725.                 do    {
  726.                     n = n * base + m;
  727.                     c = _sfget();
  728.                     m = _sfnum(c, base);
  729.                     if (--wid == 0) break;
  730.                 } while (m >= 0);
  731.                 if (!skip) {
  732.                     if (lng) {
  733.                         lp = *args++;
  734.                         *lp = n;
  735.                     }
  736.                     else    {
  737.                         ip = *args++;
  738.                         *ip = n;
  739.                     }
  740.                     assigned++;
  741.                 }
  742.                 break;
  743.             case 'e': case 'f': case 'E': case 'F':
  744.                 /* no floats implemented */
  745.                 return -2;
  746.             default:
  747.                 return assigned;
  748.             }
  749.         }
  750.     }
  751.     return f == 0 ? assigned : EOF;
  752. }
  753.  
  754.  
  755. _sfnum(c, base) {
  756.     if (c >= '0' && c <= '9')
  757.         return c - '0';
  758.     else if (base == 16 && c >= 'a' && c <= 'f')
  759.         return c - 'a' + 10;
  760.     else if (base == 16 && c >= 'A' && c <= 'F')
  761.         return c - 'A' + 10;
  762.     else     return -1;
  763. }
  764.  
  765. _sfget() {
  766.     extern char *_sfcp;
  767.     extern FILE *_sffp;
  768.     if (_sffp) return getc(_sffp);
  769.     if (_sfcp && *_sfcp) return *_sfcp++;
  770.     return EOF;
  771. }
  772.  
  773. char *_sfcp;    /* char pointer for scanf input string */
  774. FILE *_sffp;    /* FILE pointer for scanf input stream */
  775.  
  776. /* malloc, free, realloc: dynamic memory allocation */
  777.  
  778. #define MAXHUNK    512
  779.  
  780. struct header {
  781.     struct header *next;
  782.     unsigned size;
  783. };
  784.  
  785. char *
  786. malloc(n) unsigned n; {
  787.     extern struct header _base;
  788.     struct header *p, *q;
  789.     long sz;
  790.  
  791.     /* add a header to required size and round up */
  792.     n = n + sizeof(struct header);
  793.     n = (7 + n) & ~7;
  794.  
  795.     /* look for first block big enough in free list */
  796.     p = &_base;
  797.     q = _base.next;
  798.     while (q != NULL && q->size < n) {
  799.         p = q;
  800.         q = q->next;
  801.     }
  802.  
  803.     /* if not enough memory, get more from the system */
  804.     if (q == NULL) {
  805.         sz = (n > MAXHUNK ? n : MAXHUNK);
  806.         q = trap(1, 0x48, sz);
  807.         if (((long)q) < 0) /* no more memory */
  808.             return NULL;
  809.         p->next = q;
  810.         q->size = sz;
  811.         q->next = NULL;
  812.     }
  813.         
  814.     if (q->size > n + sizeof(struct header)) { /* chop it up */
  815.         q->size -= n;
  816.         q = ((long) q) + q->size;
  817.         q->size = n;
  818.     }
  819.     else    { /* unlink from free list */
  820.         p->next = q->next;
  821.     }
  822.     
  823.     /* skip over header, hope they don't touch it */
  824.     return ++q;
  825. }
  826.  
  827. free(r) struct header *r; {
  828.     extern struct header _base;
  829.     struct header *p, *q, *t;
  830.  
  831.     /* move back to uncover the header */
  832.     r--;
  833.  
  834.     /* find where to insert it */
  835.     p = &_base;
  836.     q = _base.next;
  837.     while (q != NULL && q < r) {
  838.         p = q;
  839.         q = q->next;
  840.     }
  841.  
  842.     /* merge after if possible */
  843.     t = ((long) r) + r->size;
  844.     if (q != NULL && t >= q) {
  845.         r->size += q->size;
  846.         q = q->next;
  847.     }
  848.     r->next = q;
  849.     
  850.     /* merge before if possible, otherwise link it in */
  851.     t = ((long) p) + p->size;
  852.     if (t >= r) {
  853.         p->size += r->size;
  854.         p->next = r->next;
  855.     }
  856.     else    p->next = r;
  857. }
  858.  
  859. char *
  860. realloc(r, n) struct header *r; unsigned n; {
  861.     struct header *p, *q;
  862.     long *src, *dst;
  863.     unsigned sz;
  864.  
  865.     p = r - 1;
  866.     sz = (n + sizeof(struct header) + 7) & ~7;
  867.  
  868.     if (p->size > sz) { /* block too big, split in two */
  869.         q = ((long) p) + sz;
  870.         q->size = p->size - sz;
  871.         free(q + 1);
  872.         p->size = sz;
  873.     }
  874.     else if (p->size < sz) { /* block too small, get new one */
  875.         dst = q = malloc(n);
  876.         if (q != NULL) {
  877.             src = r;
  878.             n = p->size - sizeof(struct header);
  879.             while (n > 0) {
  880.                 *dst++ = *src++;
  881.                 n -= sizeof(long);
  882.             }
  883.         }
  884.         free(r);
  885.         r = q;
  886.     }
  887.     /* else current block will do just fine */
  888.  
  889.     return r;
  890. }
  891.  
  892. char *
  893. calloc(n, sz) unsigned n, sz; {
  894.     char *r, *s;
  895.     unsigned total;
  896.  
  897.     total = n * sz;
  898.     if ((r = s = malloc(total)) != NULL) {
  899.         while (total--)
  900.             *s++ = 0;
  901.     }
  902.     return r;
  903. }
  904.  
  905. struct header _base = { NULL, 0 };
  906.  
  907. /* get options from command line */
  908.  
  909. extern char    *strchr();
  910. extern char    *optarg;
  911. extern int    optind, opterr, optsubind;
  912.  
  913. getopt(argc, argv, optstr) char *argv[], *optstr; {
  914.     char    *o, c;
  915.  
  916.     if (++optind == argc) return EOF;
  917.  
  918.     o = argv[optind];
  919.  
  920.     if (*o == '-') {
  921.         c = o[++optsubind];
  922.         if (c == '-') return EOF;
  923.         optstr = strchr(optstr, c);
  924.         if (optstr == NULL) {
  925.             if (opterr == 0) {
  926.                 fprintf(stderr, "unknown option: %s\n", o);
  927.             }
  928.             optsubind = 0;
  929.             return '?';
  930.         }
  931.         if (optstr[1] == ':') {
  932.             optarg = (o[optsubind + 1] != (char)0)
  933.                     ? o + optsubind + 1 : argv[++optind];
  934.             optsubind = 0;
  935.             if (optarg == NULL) {
  936.                 if (opterr == 0) {
  937.                     fprintf(stderr, "missing arg: %s\n", o);
  938.                 }
  939.                 return '?';
  940.             }
  941.         }
  942.         else if (o[2] != (char)0) {
  943.             optind -= 1;
  944.         }
  945.         return c;
  946.     }
  947.     return EOF;
  948. }
  949.  
  950. char    *optarg;
  951. int    optind, opterr, optsubind;
  952.  
  953. /* string routines */
  954.  
  955. #define MASK(c)    ((int)(c) & 0xff)
  956.  
  957. extern char    *_tokptr;
  958.  
  959. char *
  960. strcat(s1, s2) char *s1, *s2; {
  961.     char *r;
  962.  
  963.     r = s1;
  964.     if (*s1) while (*++s1);
  965.     while (*s1++ = *s2++);
  966.     return r;
  967. }
  968.  
  969. char *
  970. strncat(s1, s2, n) char    *s1, *s2; int n; {
  971.     char *r;
  972.  
  973.     if (n <= 0) return s1;
  974.     r = s1;
  975.     if (*s1) while (*++s1);
  976.     while (n-- && (*s1++ = *s2++));
  977.     while (n-- > 0) *s1++ = EOS;
  978.     return r;
  979. }
  980.  
  981. strcmp(s1, s2) char *s1, *s2; {
  982.     while (*s1) {
  983.         if (*s1++ != *s2++) 
  984.             return MASK(*--s1) - MASK(*--s2);
  985.     }
  986.     return -MASK(*s2);
  987. }
  988.  
  989. strncmp(s1, s2, n) char    *s1, *s2; int n; {
  990.     if (n <= 0) return 0;
  991.     while (*s1 && --n) {
  992.         if (*s1++ != *s2++) return MASK(*--s1) - MASK(*--s2);
  993.     }
  994.     return MASK(*s1) - MASK(*s2);
  995. }
  996.  
  997. char *
  998. strcpy(s1, s2) char *s1, *s2; {
  999.     char *r;
  1000.  
  1001.     r = s1;
  1002.     while (*r++ = *s2++);
  1003.     return s1;
  1004. }
  1005.  
  1006. char *
  1007. strncpy(s1, s2, n) char *s1, *s2; int n; {
  1008.     char *r;
  1009.  
  1010.     if (n <= 0) return s1;
  1011.     r = s1;
  1012.     while (n && (*r++ = *s2++)) --n;
  1013.     while (n--) *r++ = EOS;
  1014.     return s1;
  1015. }
  1016.  
  1017. strlen(s) char *s; {
  1018.     int n;
  1019.  
  1020.     for (n = 0; *s++; ++n)
  1021.         ;
  1022.     return n;
  1023. }
  1024.  
  1025. char *
  1026. strchr(s, c) char *s; int c; {
  1027.     while (*s) if (*s++ == c) return --s;
  1028.     return NULL;
  1029. }
  1030.  
  1031. char *
  1032. strrchr(s, c) char *s; int c; {
  1033.     char    *l;
  1034.  
  1035.     l = NULL;
  1036.     while (*s) 
  1037.         if (*s++ == c) 
  1038.             l = s - 1;
  1039.     return l;
  1040. }
  1041.  
  1042. char *
  1043. strpbrk(s1, s2) unsigned char *s1, *s2; {
  1044.     int    n;
  1045.     long    bitmap[16];
  1046.  
  1047.     if (*s1 || *s2) return NULL;
  1048.     _setbits(s2, bitmap);
  1049.     n = *s1;
  1050.     do    {
  1051.         if (bitmap[n >> 5] & (1 << (n & 31))) 
  1052.             return s1;
  1053.     } while (n = *--s1);
  1054.     return NULL;
  1055. }
  1056.  
  1057. char *
  1058. strtok(s1, s2) unsigned char *s1, *s2; {
  1059.     if (s1 != NULL) _tokptr = s1;
  1060.     if (*_tokptr == EOS) return NULL;
  1061.     s1 = _tokptr + strspn(_tokptr, s2);
  1062.     _tokptr = s1 + strcspn(s1, s2);
  1063.     if (_tokptr == s1) return NULL;
  1064.     if (*_tokptr != EOS) *_tokptr++ = EOS;
  1065.     return s1;
  1066. }
  1067.  
  1068. char *_tokptr;
  1069.  
  1070. strspn(s1, s2) unsigned char *s1, *s2; {
  1071.     long    n;
  1072.     long    bitmap[8];
  1073.  
  1074.     if ((*s1 == 0) || (*s2 == 0)) 
  1075.         return 0;
  1076.     _setbits(s2, bitmap);
  1077.     s2 = s1;
  1078.     for (n = *s1; bitmap[n >> 5] & (1L << (n & 31)); n = *++s1)
  1079.         ;
  1080.     return s1 - s2;
  1081. }
  1082.  
  1083. strcspn(s1, s2) unsigned char *s1, *s2; {
  1084.     long    n;
  1085.     long    bitmap[8];
  1086.  
  1087.     if ((*s1 == 0) || (*s2 == 0)) 
  1088.         return 0;
  1089.     _setbits(s2, bitmap);
  1090.     s2 = s1;
  1091.     bitmap[0] |= 1L; /* so that eos exits loop */
  1092.     for (n = *s1; (bitmap[n >> 5] & (1L << (n & 31))) == 0L; n = *++s1)
  1093.         ;
  1094.     return s1 - s2;
  1095. }
  1096.  
  1097. _setbits(s, m) unsigned char *s; long m[]; {
  1098.     unsigned long    n;
  1099.  
  1100.     for (n = 8; n; ) m[--n] = 0L;
  1101.     while (n = *s++) {
  1102.         m[n >> 5] |= 1L << (n & 31);
  1103.     }
  1104. }
  1105.  
  1106. long 
  1107. strtol(s, p, base) char    *s, **p; {
  1108.     long    r;
  1109.     int    sign, bn, bcl, bcu, c;
  1110.  
  1111.     r = 0L;
  1112.     sign = 0;
  1113.     bn = (base < 11) ? ('0' - 1) + base : '9';
  1114.     bcl = ('a' - 10) + base;
  1115.     bcu = ('A' - 10) + base;
  1116.     while (*s == ' ' || *s == '\t') ++s;
  1117.     if (*s == '-') {
  1118.         sign = 1;
  1119.         ++s;
  1120.     }
  1121.     if (*s == '0') {
  1122.         if ((s[1] == 'x' || s[1] == 'X') && (base == 16)) s += 2;
  1123.     }
  1124.     for (c = *s ; ; c = *++s) {
  1125.         if (c >= '0' && c <= bn) 
  1126.             c = c - '0';
  1127.         else if (c >= 'a' && c < bcl) 
  1128.             c = c - 'a' + 10;
  1129.         else if (c >= 'A' && c < bcu) 
  1130.             c = c - 'A' + 10;
  1131.         else    {
  1132.             if (p != NULL) *p = s;
  1133.             return sign ? -r : r;
  1134.         }
  1135.         r = r * base + c;
  1136.     }
  1137. }
  1138.  
  1139. char *
  1140. strlower(s) char *s; {
  1141.     char c, *p;
  1142.  
  1143.     for (p = s; c = *p; ++p) 
  1144.         if (c >= 'A' && c <= 'Z') 
  1145.             *p = c - ('A' - 'a');
  1146.     return s;
  1147. }
  1148.  
  1149. char *
  1150. strupper(s) char *s; {
  1151.     char c, *p;
  1152.  
  1153.     for (p = s; c = *p; ++p) 
  1154.         if (c >= 'a' && c <= 'z') 
  1155.             *p = c - ('a' - 'A');
  1156.     return s;
  1157. }
  1158.  
  1159. memcpy(m1, m2, n) char *m1, *m2; {
  1160.     while (n-- > 0) 
  1161.         *m1++ = *m2++;
  1162. }
  1163.  
  1164. /* a UNIX style time command */
  1165.  
  1166. extern int _ma[];
  1167.  
  1168. long
  1169. time(tloc) long *tloc; {
  1170.     int    n, hms, y, m, d;
  1171.     long    t;
  1172.  
  1173.     n = getdate();
  1174.     y = (n >> 9) & 127; m = (n >> 5) & 15; d = n & 31;
  1175.     hms = gettime();
  1176.     t = (1460 * y) / 4 + ((y % 4) ? 1 : 0) + _ma[m] + d;
  1177.     t = 2L * (long)(hms & 31)
  1178.         + 60L * (long)((hms >> 5) & 63)
  1179.         + 3600L * (24L * t + (long)((hms >> 11) & 31));
  1180.     if (tloc != NULL) *tloc = t;
  1181.     return t;
  1182. }
  1183.  
  1184. getdate() { return trap(1, 0x2A); }
  1185.  
  1186. gettime() { return trap(1, 0x2C); }
  1187.  
  1188. int _ma[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
  1189.  
  1190. /* setjmp/longjmp thanks to Bruce Szablak, use setjmp.h! */
  1191.  
  1192. setjmp(buf) char **buf; {
  1193.     asm( lll 8 0);
  1194.     asm( tda 0 0); /* a0 has pointer to buffer */
  1195.     asm( tad 6 0); /* d0 has current link pointer */
  1196.     asm( sol 0 0 0); /* save clp */
  1197.     asm( lol 6 0 0); /* d0 has old link pointer */
  1198.     asm( sol 0 4 0); /* save olp */
  1199.     asm( lol 6 4 0); /* d0 has return address */
  1200.     asm( sol 0 8 0); /* save ret */
  1201.     return 0;
  1202. }
  1203.  
  1204. longjmp(buf, rc) char **buf; {
  1205.     asm( lll 8 0);
  1206.     asm( tda 0 0); /* buf in a0 */
  1207.     asm( llw 12 0); /* rc in d0 */
  1208.     asm( lol 0 0 1); /* current link pointer */
  1209.     asm( tda 1 6); /* now in a6 */
  1210.     asm( lol 0 4 1); /* old link pointer */
  1211.     asm( sll 1 0); /* now on stack */
  1212.     asm( lol 0 8 1); /* return address */
  1213.     asm( sll 1 4); /* now on stack */
  1214.     return; /* longjmp! */
  1215. }    
  1216.  
  1217. /* 
  1218.  * stuff for long binary ops (both signed and unsigned)
  1219.  *    op == 0 for a multiplication request
  1220.  *    op == 1 for a division
  1221.  *    op == 2 for a mod operation
  1222.  *    a and b are the left and right arguments to the binary operator
  1223.  *
  1224.  * div and mod are done by long division, shift b up until >= a, then
  1225.  * back down, subtracting when appropriate
  1226.  *
  1227.  * mul is done by shifts and adds
  1228.  */
  1229.  
  1230. #define MUL    0
  1231. #define DIV    1
  1232. #define MOD    2
  1233.  
  1234. long
  1235. _lop(op, a, b) int op; long a, b; {
  1236.     int neg;
  1237.     long result, _ulop();
  1238.     neg = 0;
  1239.     if (a < 0) {
  1240.         neg++;
  1241.         a = -a;
  1242.     }
  1243.     if (b < 0) {
  1244.         neg++;
  1245.         b = -b;
  1246.     }
  1247.     result = _ulop(op, a, b);
  1248.     return (((op != MOD) && (neg & 1)) ? -result : result);
  1249. }
  1250.  
  1251. long
  1252. _ulop(op, xx, yy) int op; unsigned long xx, yy; {
  1253.     int i;
  1254.     unsigned long result, x, y;
  1255.     x = xx;
  1256.     y = yy;
  1257.     if (op == MUL) {
  1258.         result = 0L;
  1259.         while (x) {
  1260.             if (x & 1L)
  1261.                 result += y;
  1262.             x >>= 1L;
  1263.             y <<= 1L;    
  1264.         }
  1265.     }
  1266.     else    { /* DIV or MOD */
  1267.         i = 0;
  1268.         result = x > 0x80000000L ? 0x80000000L : x;
  1269.         while (y < result) {
  1270.             i++;
  1271.             y <<= 1L;
  1272.         }
  1273.         result = 0L;
  1274.         while (i) {
  1275.             if (x >= y) {
  1276.                 x -= y;
  1277.                 result++;
  1278.             }
  1279.             i--;
  1280.             result <<= 1L;
  1281.             y >>= 1L;
  1282.         }
  1283.         if (x >= y) {
  1284.             x -= y;
  1285.             result++;
  1286.         }
  1287.         if (op == MOD) result = x;
  1288.     }
  1289.     return result;
  1290. }
  1291.  
  1292.